/*
 * Copyright (C) 2011 Christopher Probst
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *  
 * * Neither the name of the 'FoxNet Codec' nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.foxnet.codec;

/**
 * <h1>CachePolicy</h1>
 * <p>
 * If you write an object the {@link ObjectOutputChannel} will use its
 * <code>CachePolicy</code> to determine whether or not the object should be
 * cached.
 * </p>
 * <h3>When to use which CachePolicy ?</h3>
 * <p>
 * Basically caching is senseless if you do not write identical objects more
 * than once. For instance: If you have a list of strings with random content
 * caching causes some overhead because the <code>OStream</code> stores internal
 * references to those strings in its {@link Cache} without actually using them.
 * In such a case you should use the default {@link CachePolicy.None} instance.
 * This instance will never cache anything so there will not be any overhead.
 * </p>
 * <p>
 * Whether to cache or not depends also on your requirements:
 * <ul>
 * <li>If you need the best data compression you should always use the default
 * {@link CachePolicy.Recursive} instance.</li>
 * <li>If you need the best performance you should use a
 * <code>CachePolicy</code> depending on what type of data you write. For
 * instance: If you write a lot of redundant data caching can be faster if your
 * data segments are big enough. For instance, it will not make sense to cache
 * short strings (0-20 bytes) since writing them is faster than caching. Also if
 * you mainly write different data caching can be a loss.</li>
 * <li>If you write data with circular references you should use the
 * <code>CachePolicy.Recursive</code> instance. Otherwise you could cause an
 * infinite loop.</li>
 * </ul>
 * </p>
 * 
 * @author Christopher Probst
 */
public interface CachePolicy {

    /**
     * <p>
     * This <code>CachePolicy</code> never caches anything.
     * </p>
     */
    CachePolicy None = new CachePolicy() {

	@Override
	public boolean isCacheObject(ObjectOutputChannel<?> output, Object object) {
	    return false;
	}
    };

    /**
     * <p>
     * This <code>CachePolicy</code> always caches all objects.
     * </p>
     */
    CachePolicy Recursive = new CachePolicy() {

	@Override
	public boolean isCacheObject(ObjectOutputChannel<?> output, Object object) {
	    return true;
	}
    };

    /**
     * <p>
     * This <code>CachePolicy</code> always caches all objects except arrays.
     * This is the default cache policy.
     * </p>
     */
    CachePolicy RecursiveNoArrays = new CachePolicy() {

	@Override
	public boolean isCacheObject(ObjectOutputChannel<?> output, Object object) {
	    return !object.getClass().isArray();
	}
    };

    /**
     * <p>
     * This <code>CachePolicy</code> only caches the root object which is being
     * written using {@link ObjectOutputChannel#writeObject(Object)}. If the {@link Codec}
     * of this object recursively invokes
     * <code>Output.writeObject(Object)</code> nothing will be cached.
     * </p>
     */
    CachePolicy Shallow = new CachePolicy() {

	@Override
	public boolean isCacheObject(ObjectOutputChannel<?> output, Object object) {
	    return output.getRecursiveDepth() == 1;
	}
    };

    /**
     * <p>
     * Returns whether or not the given object should be cached.
     * </p>
     * 
     * @param output
     *            The {@link ObjectOutputChannel} which writes the given object.
     * @param object
     *            The object which is going to be cached.
     * @return Returns <code>true</code> if the object should be cached,
     *         otherwise <code>false</code>.
     */
    boolean isCacheObject(ObjectOutputChannel<?> output, Object object);
}
